package org.balthie.demo.jdk.util.concurrent.auxiliary.exchanger;

import java.util.concurrent.Exchanger;

//Thread1线程到达栅栏后，会首先观察有没其它线程已经到达栅栏，如果没有就会等待，如果已经有其它线程（Thread2）已经到达了，
//就会以成对的方式交换各自携带的信息，因此Exchanger非常适合用于两个线程之间的数据交换。

//首先到达的线程：
//如果当前线程是首个到达的线程，会将slot字段指向自身的Node结点，表示槽位被占用；
//然后，线程会自旋一段时间，如果经过一段时间的自旋还是等不到配对线程到达，就会进入阻塞。（这里之所以不直接阻塞，而是自旋，是出于线程上下文切换开销的考虑，属于一种优化手段）

//稍后到达的配对线程：
//如果当前线程（配对线程）不是首个到达的线程，则到达时槽（slot）已经被占用，此时slot指向首个到达线程自身的Node结点。配对线程会将slot置空，并取Node中的item作为交换得到的数据返回，另外，配对线程会把自身携带的数据存入Node的match字段中，并唤醒Node.parked所指向的线程（也就是先到达的线程）。

//当并发量低的时候，内部采用“单槽位交换”；  并发量高的时候会采用“多槽位交换”。 Exchange.exchange(V x) 
//“单槽位交换”: 条件 arena==null
//“多槽位交换”: 条件 arena!=null

// Exchange.slot : 前一个到达 同步点的线程

//https://segmentfault.com/a/1190000015963932
public class Producer implements Runnable {
	private final Exchanger<Message> exchanger;

	public Producer(Exchanger<Message> exchanger) {
		this.exchanger = exchanger;
	}

	@Override
	public void run() {
		Message message = new Message(null);
		for (int i = 0; i < 3; i++) {
			try {
				Thread.sleep(1000);

				message.setV(String.valueOf(i));
				System.out.println(Thread.currentThread().getName() + ": 生产了数据[" + i + "]");

				message = exchanger.exchange(message);

				System.out
						.println(Thread.currentThread().getName() + ": 交换得到数据[" + String.valueOf(message.getV()) + "]");

			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}
	}
}
